﻿#pragma once

#include <ctime>
#include <list>
#include <memory>
#include <sstream>
#include <string>

namespace kratos {
namespace util {

/**
 * 定时器节点回调
 */
class InterTimerNodeCallback {
public:
  /**
   * 析构
   */
  virtual ~InterTimerNodeCallback() {}
  /**
   * 执行一次
   * @retval false 任务将被删除
   * @retval true 任务下次还继续被调用
   */
  virtual bool do_task() = 0;
  /**
   * 获取任务名称.
   *
   * \return 任务名称
   */
  auto get_name() const noexcept -> const std::string &;

protected:
  std::string name_; ///< 任务名称
};

/**
 * 定时器接口
 */
class InterTimer {
public:
  /**
   * 虚析构
   */
  virtual ~InterTimer() {}

  /**
   * 测试是否过期
   * @param ms 当前时间戳(毫秒)
   * @retval true 到期
   * @retval false 未到期
   */
  virtual bool is_expired(std::time_t ms) = 0;

  /**
   * 重置
   * @param ms 当前时间戳(毫秒)
   * @param duration 持续时间(毫秒)
   * @param fireNow 是否立即触发
   */
  virtual void reset(std::time_t ms, std::time_t duration,
                     bool fireNow = false) = 0;

  /**
   * 取消定时器
   */
  virtual void cancel() = 0;

  /**
   * 检测是否已经取消
   * @retval true 是
   * @retval false 否
   */
  virtual bool cancelled() = 0;

  /**
   * 暂停定时器
   */
  virtual void suspend() = 0;

  /**
   * 恢复定时器
   */
  virtual void resume() = 0;

  /**
   * 定时器是否已经启动
   * @retval true 是
   * @retval false 否
   */
  virtual bool is_started() = 0;
};

/**
 * 运行无限次的定时器
 */
class InterDurationTimer : public InterTimer {
public:
  /**
   * 构造
   */
  InterDurationTimer();

  /**
   * 构造
   * @param ms 当前时间戳(毫秒)
   * @param duration 持续时间(毫秒)
   * @param fireNow 建立后可以立即被触发无论是否过期
   */
  InterDurationTimer(std::time_t ms, std::time_t duration,
                     bool fireNow = false);

  /**
   * 虚析构
   */
  virtual ~InterDurationTimer();
  virtual bool is_expired(std::time_t ms);
  virtual void reset(std::time_t ms, std::time_t duration,
                     bool fireNow = false);
  virtual void cancel();
  virtual bool cancelled();
  virtual void suspend();
  virtual void resume();
  virtual bool is_started();
  /**
   * 取得过期次数
   * @return 过期次数
   */
  std::time_t get_expired_times();

private:
  std::time_t ts_{0};            ///< 上一次时间戳
  std::time_t duration_{0};      ///< 持续时间
  std::time_t expired_times_{0}; ///< 过期次数
  bool fire_now_{false};   ///< 建立后可以立即被触发无论是否过期
  bool is_cancel_{false};  ///< 取消标志
  bool is_suspend_{false}; ///< 是否暂停
  std::time_t rest_time_{0}; ///< 剩余时间
};

#define CLASS_FIELD(name, type) type name##_;

class InterTimerNode;

using ChildPtr = std::shared_ptr<kratos::util::InterTimerNode>;
using CbPtr = std::shared_ptr<kratos::util::InterTimerNodeCallback>;

/**
 * 定时器节点
 */
class InterTimerNode {
  using ChildNodePtr = std::weak_ptr<kratos::util::InterTimerNode>;
  using NodeCbPtr = std::weak_ptr<kratos::util::InterTimerNodeCallback>;

public:
  /**
   * 构造
   * @param level 父节点层级
   * @param duration 定时器超时间隔(毫秒)
   * @param name 名字
   */
  InterTimerNode(int level, std::time_t duration, const std::string &name);

  /**
   * 析构
   */
  ~InterTimerNode();

  /**
   * 在队列尾添加节点任务, 定时器超时时将被执行
   * @param task 任务回调
   * @retval true 成功
   * @retval false 失败
   */
  bool add_task_back(CbPtr task);

  /**
   * 在队列头添加节点任务, 定时器超时时将被执行
   * @param task 任务回调
   * @retval true 成功
   * @retval false 失败
   */
  bool add_task_front(CbPtr task);

  /**
   * 销毁任务
   * @param task 任务
   */
  void del_task(CbPtr task);

  /**
   * 在队列头添加子节点
   * @param duration 子节点超时间隔
   * @param name 节点名字
   * @return 节点实例
   */
  ChildPtr add_child_front(std::time_t duration, const std::string &name);

  /**
   * 在队列尾添加子节点
   * @param duration 子节点超时间隔
   * @param name 节点名字
   * @return 节点实例
   */
  ChildPtr add_child_end(std::time_t duration, const std::string &name);

  /**
   * 运行一次循环
   * @param ms 当前时间戳（毫秒）
   */
  void update(std::time_t ms);

  /**
   * 运行一次循环, 并且记录性能数据
   * @param ms 当前时间戳（毫秒）
   * @return 本次循环所调用的回调数量
   */
  uint32_t update_profile(std::time_t ms);

  /**
   * 获取详细的性能报告
   */
  void get_detail_report(std::stringstream &profile);

  /**
   * 获取详细的性能报告
   */
  void get_tree_report(std::stringstream &profile);

  /**
   * 获取简略的性能报告
   */
  void get_brief_report(std::stringstream &profile);
  /**
   * 本轮，节点，包含子孙节点总的消耗(微秒)
   *
   * \return 本轮，节点，包含子孙节点总的消耗(微秒)
   */
  auto get_total_cost() -> std::time_t;
  /**
   * 本轮，本节点消耗的时间(微秒).
   *
   * \return 本轮，本节点消耗的时间(微秒)
   */
  auto get_cost() -> std::time_t;
  /**
   * 当前处于树的层次深度.
   *
   * \return 当前处于树的层次深度
   */
  auto get_level() -> int;

private:
  /**
   * 缩进
   */
  std::stringstream &indent(std::stringstream &profile);

private:
  CLASS_FIELD(total_cost,
              std::time_t) ///< 本轮，节点，包含子孙节点总的消耗(微秒)
  CLASS_FIELD(cost, std::time_t) ///< 本轮，本节点消耗的时间(微秒)
  CLASS_FIELD(total_run_cb,
              uint32_t) ///< 本轮一共运行了多少个回调，包含子孙节点
  CLASS_FIELD(all_total_cost,
              std::time_t) ///< 节点，包含子孙节点历史累计总消耗(微秒)
  CLASS_FIELD(all_cost, std::time_t) ///< 本节点历史累计总消耗(微秒)
  CLASS_FIELD(level, int)            ///< 当前处于树的层次深度
  CLASS_FIELD(timer, InterDurationTimer) ///< 定时器
  CLASS_FIELD(name, std::string)         ///< 节点名称
  CLASS_FIELD(avg_total_cost,
              std::time_t) ///< 节点，包含子孙节点平均总消耗（微秒）
  CLASS_FIELD(avg_cost, std::time_t) ///< 本节点平均消耗的时间(微秒)
  CLASS_FIELD(run_times, std::time_t) ///< 循环调用次数
  CLASS_FIELD(min_cost, std::time_t)  ///< 本节点历史最低消耗(微秒)
  CLASS_FIELD(max_cost, std::time_t)  ///< 本节点历史最高消耗(微秒)
  CLASS_FIELD(min_total_cost,
              std::time_t) ///< 节点，包含子孙节点历史最低消耗(微秒)
  CLASS_FIELD(max_total_cost,
              std::time_t) ///< 节点，包含子孙节点历史最高消耗(微秒)
  /**
   * 任务信息
   */
  struct CbInfo {
    NodeCbPtr cb;              ///< 任务回调
    std::time_t cost{0};       ///< 消耗的时间（微秒）
    std::time_t total_cost{0}; ///< 总消耗时间（微秒）
    bool result{false};        ///< 本次执行结果
    std::time_t run_times{0};  ///< 总调用次数
    std::time_t min_cost{0};   ///< 历史最低消耗
    std::time_t max_cost{0};   ///< 历史最高消耗
  };
  typedef std::list<CbInfo> CbList;
  typedef std::list<ChildNodePtr> NodeList;
  CLASS_FIELD(cbs, CbList) ///< 本节点的任务回调，保证严格按照插入顺
  CLASS_FIELD(children, NodeList) ///< 子节点列表
};

} // namespace util
} // namespace kratos
